package com.qqt.csr.im.service.sensitiveword;

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.thread.ThreadUtil;
import com.github.houbb.sensitive.word.bs.SensitiveWordBs;
import com.obs.services.exception.ObsException;
import com.qqt.csr.common.enums.YesOrNotEnum;
import com.qqt.csr.common.exception.BizException;
import com.qqt.csr.common.utils.SnowflakeUtil;
import com.qqt.csr.im.dto.SensitiveWordRefreshDTO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.MDC;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Component
public class SensitiveWordRefreshTimer implements InitializingBean {
    private static final String LOG_TID = "ctid";
    private final ScheduledThreadPoolExecutor executor = ThreadUtil.createScheduledExecutor(1);
    /**
     * 最近一次更新敏感词更新时间
     */
    private Date lastSwRefreshTime;

    private int size = 3000;

    @Autowired
    private SensitiveWordBsFactory sensitiveWordBsFactory;
    @Autowired
    private SensitiveWordService sensitiveWordService;
    @Autowired
    private SensitiveWordTagService sensitiveWordTagService;

    @Override
    public void afterPropertiesSet() throws Exception {
        lastSwRefreshTime = DateUtil.offsetMinute(new Date(), -5);
        ThreadUtil.schedule(executor,
                () -> {
                    try {
                        MDC.put(LOG_TID, SnowflakeUtil.nextIdStr());
                        this.refresh();
                    } catch (Throwable e) {
                        log.error("定时刷新敏感词工具异常！", e);
                    } finally {
                        MDC.clear();
                    }
                },
                30,
                15,
                TimeUnit.SECONDS,
                false
        );
    }

    /**
     * 以敏感词的更新时间作为水位线，刷新敏感词
     */
    public synchronized void refresh() {
        int pageIndex = 0;
        Long lastId = 0L;
        do {
            List<SensitiveWordRefreshDTO> sensitiveWordList = sensitiveWordService.getWordListForRefresh(lastSwRefreshTime, pageIndex, size);
            if (CollectionUtils.isEmpty(sensitiveWordList)) {
                lastSwRefreshTime = DateUtil.offset(lastSwRefreshTime, DateField.MILLISECOND, 1);
                break;
            }

            SensitiveWordRefreshDTO lastSw = sensitiveWordList.get(sensitiveWordList.size() - 1);
            if (lastId.equals(lastSw.getSwId()) && lastSwRefreshTime.equals(lastSw.getSwUpdateTime())) {
                // 避免最后的数据被用来循环更新多次
                lastSwRefreshTime = DateUtil.offset(lastSwRefreshTime, DateField.MILLISECOND, 1);
                break;
            }
            lastId = lastSw.getSwId();

            Map<String, List<SensitiveWordRefreshDTO>> tenantIdSwList = sensitiveWordList.stream().collect(Collectors.groupingBy(SensitiveWordRefreshDTO::getTenantId));
            tenantIdSwList.forEach(this::doRefreshSensitiveWordBs);

            if (lastSw.getSwUpdateTime().equals(lastSwRefreshTime)) {
                // 避免导入超过size=3000条敏感词时，还有在下一页的相同更新时间的敏感词没被查出来
                pageIndex++;
            } else {
                lastSwRefreshTime = lastSw.getSwUpdateTime();
                pageIndex = 0;
            }
            log.info("本地敏感词工具类同步，查询到最新的敏感词id:{},updateTime:{}", lastId, lastSw.getSwUpdateTime());
        } while (true);
    }

    /**
     * 刷新敏感词工具
     *
     * @param tenantId
     * @param swList
     */
    private void doRefreshSensitiveWordBs(String tenantId, List<SensitiveWordRefreshDTO> swList) {
        Set<String> removeWordSet = new HashSet<>();
        Set<String> addWordSet = new HashSet<>();

        for (SensitiveWordRefreshDTO sw : swList) {
            if (sw.getSwEnable().equals(YesOrNotEnum.YES.getValue())
                    && sw.getSwDeleteFlag().equals(YesOrNotEnum.NOT.getValue())
                    && sw.getSwpEnable().equals(YesOrNotEnum.YES.getValue())
                    && sw.getSwpDeleteFlag().equals(YesOrNotEnum.NOT.getValue())) {
                addWordSet.add(sw.getSwName());
                // 更新敏感词的标签
                sensitiveWordTagService.addTag(sw.getSwName(), tenantId, sw.getRepoId());
            } else {
                removeWordSet.add(sw.getSwName());
            }
        }

        SensitiveWordBs sensitiveWordBs = sensitiveWordBsFactory.getSensitiveWordBs(tenantId);
        // 移除失效的敏感词
        sensitiveWordBs.removeWord(removeWordSet);
        // 刷新生效的敏感词
        sensitiveWordBs.addWord(addWordSet);
    }


}
